package com.ums.upos.service;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.Typeface;
import android.os.Build;
import android.util.Base64;

import com.nexgo.oaf.apiv3.SdkResult;
import com.nexgo.oaf.apiv3.device.printer.AlignEnum;
import com.nexgo.oaf.apiv3.device.printer.BarcodeFormatEnum;
import com.nexgo.oaf.apiv3.device.printer.DotMatrixFontEnum;
import com.nexgo.oaf.apiv3.device.printer.FontEntity;
import com.nexgo.oaf.apiv3.device.printer.GrayLevelEnum;
import com.nexgo.oaf.apiv3.device.printer.LineOptionEntity;
import com.nexgo.oaf.apiv3.device.printer.Printer;
import com.ums.upos.GlobalDataHolder;
import com.ums.upos.util.MachineModelUtils;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.InvalidParameterException;

/**
 * Created by Administrator on 2017/4/10.
 */

public class PrintScript {
    private int _type;
    private String _cmd;
    private String _paramStr;
    private boolean testMode = false;

    public final int type() {
        return _type;
    }

    public final String cmd() {
        return _cmd;
    }

    public final String param() {
        return _paramStr;
    }

    static class PrintScritType {
        public final static int SET_PARAM = 0;
        public final static int ADD_DATA = 1;
    }

    static class GlobalParam {
        static class BarcodeParam {
            int singleBarWidth;
            int height;
        }

        static class QrcodeParam {
            int height;
            int errorCorrectionLevel;
        }

        static class FontParam {
            int size;
            Typeface hzTypeface;
            Typeface ascTypeface;
            DotMatrixFontEnum hzFont;
            DotMatrixFontEnum ascFont;
            boolean isXZoom;
            boolean isYZoom;
            int printMode;
        }

        BarcodeParam barcodeParam = new BarcodeParam();
        QrcodeParam qrcodeParam = new QrcodeParam();
        FontParam fontParam = new FontParam();
        int printerWidth;
//        int grayLeve = 6;
        Context mContext;
        Printer sdkPrinter;

        GlobalParam(Printer printer, Context context) {
            barcodeParam.singleBarWidth = 2;
            barcodeParam.height = 64;

            qrcodeParam.errorCorrectionLevel = 2;
            qrcodeParam.height = 100;

            fontParam.size = 24;
            fontParam.ascFont = DotMatrixFontEnum.ASC_SONG_16X24;
            fontParam.hzFont = DotMatrixFontEnum.CH_SONG_24X24;
            fontParam.isXZoom = false;
            fontParam.isYZoom = false;
            fontParam.printMode = 3;

            printerWidth = 384;
            sdkPrinter = printer;
            mContext = context;
        }


    }

    private GlobalParam _gParam;

    private PrintScript(String scriptStr, GlobalParam gParam) {
        if ('!' == scriptStr.charAt(0))
            _type = PrintScritType.SET_PARAM;
        else if ('*' == scriptStr.charAt(0))
            _type = PrintScritType.ADD_DATA;

        String[] spilts = scriptStr.substring(1).trim().split(" ", 2);
        _cmd = spilts[0];
        if (spilts.length > 1)
            _paramStr = spilts[1];
        _gParam = gParam;
    }

    public static PrintScript create(String scriptStr, GlobalParam gParam) {
        if (null == scriptStr || null == gParam || (scriptStr.charAt(0) != '!' && scriptStr.charAt(0) != '*'))
            throw new InvalidParameterException();
        return new PrintScript(scriptStr, gParam);
    }

    boolean execute() {
        boolean rslt = false;
        if (PrintScritType.SET_PARAM == _type)
            rslt = dealSetCommand();
        else if (PrintScritType.ADD_DATA == _type)
            rslt = dealAddDataCommand();
        return rslt;
    }

    boolean dealSetCommand() {
        String params[];
        boolean rslt = true;
        switch (_cmd) {
            case "hz":
                switch (_paramStr.toLowerCase()) {
                    case "s":
                    case "sn":
                    case "sl":
                        _gParam.fontParam.hzFont = DotMatrixFontEnum.CH_SONG_16X16;
//                        _gParam.fontParam.size = 16;
                        _gParam.fontParam.size = 18;
//                        _gParam.fontParam.size = testMode ? 16 : 20;
                        break;
                    case "n":
                    case "nl":
                        _gParam.fontParam.hzFont = DotMatrixFontEnum.CH_SONG_24X24;
                        _gParam.fontParam.size = 24;
//                        _gParam.fontParam.size = testMode ? 21 : 24;
                        break;
                    case "l":
                        _gParam.fontParam.hzFont = DotMatrixFontEnum.CH_SONG_32X32;
                        _gParam.fontParam.size = 32;
//                        _gParam.fontParam.size = testMode ? 26 : 28;
                        break;
                    default:
                        _gParam.fontParam.hzFont = DotMatrixFontEnum.CH_SONG_24X24;
                        _gParam.fontParam.size = 24;
//                        _gParam.fontParam.size = testMode ? 21 : 24;
                        break;
                }
                break;
            case "asc":
                switch (_paramStr.toLowerCase()) {
                    case "s":
                    case "sn":
                    case "sl":
                        _gParam.fontParam.ascFont = DotMatrixFontEnum.ASC_SONG_8X16;
//                        _gParam.fontParam.size = 16;
                        _gParam.fontParam.size = 18;
//                        _gParam.fontParam.size = testMode ? 16 : 20;
                        break;
                    case "n":
                    case "nl":
                        _gParam.fontParam.ascFont = DotMatrixFontEnum.ASC_SONG_12X24;
                        _gParam.fontParam.size = 24;
//                        _gParam.fontParam.size = testMode ? 21 : 24;
                        break;
                    case "l":
                        _gParam.fontParam.ascFont = DotMatrixFontEnum.ASC_SONG_16X32;
                        _gParam.fontParam.size = 32;
//                        _gParam.fontParam.size = testMode ? 26 : 28;
                        break;
                    default:
                        _gParam.fontParam.ascFont = DotMatrixFontEnum.ASC_SONG_12X24;
                        _gParam.fontParam.size = 24;
//                        _gParam.fontParam.size = testMode ? 21 : 24;
                        break;
                }
                break;
//            case "gray":
//                int level = Integer.parseInt(_paramStr);
//                _gParam.grayLeve = level;
//                if (level < 1 || level > 10)
//                    _gParam.sdkPrinter.setGray(GrayLevelEnum.LEVEL_1);
//                else if (level < 4)
//                    _gParam.sdkPrinter.setGray(GrayLevelEnum.LEVEL_0);
//                else if (level < 7)
//                    _gParam.sdkPrinter.setGray(GrayLevelEnum.LEVEL_1);
//                else if (level <= 10)
//                    _gParam.sdkPrinter.setGray(GrayLevelEnum.LEVEL_2);
//                _gParam.sdkPrinter.setGray(GrayLevelEnum.LEVEL_0);
//                break;
            case "yspace":
                int spacing = Integer.parseInt(_paramStr);
                if (spacing < 1 && spacing > 60)
                    _gParam.sdkPrinter.setLetterSpacing(2);
                else
                    _gParam.sdkPrinter.setLetterSpacing((spacing < 6) ? 2 : spacing - 4);
                break;
            case "barcode":
                params = _paramStr.split(" ");
                if (params.length != 2)
                    throw new InvalidParameterException("dealSetCommand cmd:" + _cmd + " param:" + _paramStr);
                _gParam.barcodeParam.singleBarWidth = Integer.parseInt(params[0]);
                _gParam.barcodeParam.height = Integer.parseInt(params[1]);
                break;
            case "qrcode":
                params = _paramStr.split(" ");
                if (params.length != 2)
                    throw new InvalidParameterException("dealSetCommand cmd:" + _cmd + " param:" + _paramStr);
                _gParam.qrcodeParam.height = Integer.parseInt(params[0]);
                _gParam.qrcodeParam.errorCorrectionLevel = Integer.parseInt(params[1]);
                break;
            case "NLFONT":
                params = _paramStr.split(" ");
                if (params.length != 3 && params.length != 2)
                    throw new InvalidParameterException("dealSetCommand cmd:" + _cmd + " param:" + _paramStr);
 /*               for(int i = 0;i<2;i++){
                    int fontIndex = Integer.parseInt(params[i]);
                    String fontPath = "";
                    switch (fontIndex){
                        case 0://微软雅黑
                            fontPath = "fonts/msyh.ttc";break;
                        case 1://楷体-简
                            fontPath = "fonts/simkai.ttf";break;
                        case 2://宋体
                            fontPath = "fonts/simsun.ttc";break;
                        case 3://Impact Regular
                            fontPath = "fonts/impact.ttf";break;
                        case 4://Avenir Next Condensed Bold
                            fontPath = "fonts/AvenirNextCondensedBold.ttf";break;
                        case 5://Avenir Next Condensed Bold
                            fontPath = "fonts/文泉驿等宽微米黑.ttf";break;
                        case 6://Avenir Next Condensed Bold
                            fontPath = "fonts/simfang.ttf";break;
//                        case 7://Avenir Next Condensed Bold
//                            fontPath = "fonts/AvenirNextCondensedBold.ttf";break;
                        default:
                            break;
                    }
                    Typeface typeface = Typeface.createFromAsset(_gParam.mContext.getAssets(), fontPath);
                    if(0 == i) {
                        _gParam.fontParam.hzTypeface = typeface;
                        if(_gParam.fontParam.ascTypeface == null)
                            _gParam.sdkPrinter.setTypeface(typeface);
                    }
                    else {
                        _gParam.fontParam.ascTypeface = typeface;
                        _gParam.sdkPrinter.setTypeface(typeface);
                    }
                }*/
                _gParam.fontParam.printMode = Integer.parseInt(params[2]);
                switch (_gParam.fontParam.printMode) {
                    case 0:
                        _gParam.fontParam.isXZoom = true;
                        _gParam.fontParam.isYZoom = true;
                        break;
                    case 1:
                        _gParam.fontParam.isXZoom = true;
                        _gParam.fontParam.isYZoom = false;
                        break;
                    case 2:
                        _gParam.fontParam.isXZoom = false;
                        _gParam.fontParam.isYZoom = true;
                        break;
                    case 3:
                    default:
                        _gParam.fontParam.isXZoom = false;
                        _gParam.fontParam.isYZoom = false;
                        break;
                }
                break;
            case "NLPRNOVER":
                _gParam.sdkPrinter.appendPrnStr(" ", Build.MODEL.equals(MachineModelUtils.G870) ? 80 : 150, AlignEnum.LEFT, false);
                break;
            default:
                rslt = false;
        }
        return rslt;
    }

    private static class AlignParam {
        boolean bIsOffsetPxMode;
        AlignEnum alignType;
        int offsetPx;
    }

    private AlignParam ParseDispPositionParam(String param) {
        AlignParam alignParam = new AlignParam();
        alignParam.bIsOffsetPxMode = false;
        switch (param.charAt(0)) {
            case 'l':
                alignParam.alignType = AlignEnum.LEFT;
                break;
            case 'c':
                alignParam.alignType = AlignEnum.CENTER;
                break;
            case 'r':
                alignParam.alignType = AlignEnum.RIGHT;
                break;
            case 'x':
                alignParam.bIsOffsetPxMode = true;
                alignParam.offsetPx = Integer.parseInt(param.split(":")[1]);
                break;
        }
        return alignParam;
    }

    boolean dealAddDataCommand() {
        String params[];
        boolean bIsUnderline = false;
        boolean rslt = true;
        AlignParam alignParam;
        try {
            int result = SdkResult.Fail;
            switch (_cmd) {
                case "underline":
                    bIsUnderline = true;
                case "text":
                    params = _paramStr.split(" ", 2);
                    if (params.length == 1){
                        String param0 = params[0];
                        params = new String[2];
                        params[0] = param0;
                        params[1] = " ";
                    }else if (params.length != 2)
                        throw new InvalidParameterException("dealAddDataCommand cmd:" + _cmd + " param:" + _paramStr);
                    alignParam = ParseDispPositionParam(params[0]);
                    LineOptionEntity lineOption = new LineOptionEntity();
                    lineOption.setUnderline(bIsUnderline);
                    //mhl20171101 根据上层设置的灰度控制是否加粗
//                    if(_gParam.grayLeve > 5)
//                        lineOption.setBold(true);
//                    else
//                        lineOption.setBold(false);
                    lineOption.setBold(true);
                    if(GlobalDataHolder.getInstance().isSupportDotMatrix()){
                        FontEntity font = new FontEntity(_gParam.fontParam.hzFont, _gParam.fontParam.ascFont);
                        font.setZoomX(_gParam.fontParam.isXZoom);
                        font.setZoomY(_gParam.fontParam.isYZoom);
                        result = _gParam.sdkPrinter.appendPrnStr(params[1], font, alignParam.alignType, lineOption);
                    }
                    else{
                        if (params[1].equals("...............................................")) {
                            params[1] = params[1].substring(7);
                        }
                        result = _gParam.sdkPrinter.appendPrnStr(params[1], _gParam.fontParam.size, alignParam.alignType, lineOption);
                    }
                    break;
                case "feedline":
                    int value = Integer.parseInt(_paramStr);
                    if (value > 0)
                        result = _gParam.sdkPrinter.appendPrnStr(" ", value * 16, AlignEnum.LEFT, false);
                    else
                        result = SdkResult.Success;
                    break;
                case "line":
                    StringBuffer buf = new StringBuffer();
                    int num = _gParam.printerWidth / 8;
                    for (int i = 0; i < num; i++) {
                        buf.append('-');
                    }
//                    result = _gParam.sdkPrinter.appendPrnStr(buf.toString(), new FontEntity(DotMatrixFontEnum.ASC_SONG_12X24), AlignEnum.LEFT, null);
                    result = _gParam.sdkPrinter.appendPrnStr(buf.toString(), 28, AlignEnum.LEFT, false);
                    break;
                case "barcode":
                    params = _paramStr.split(" ", 2);
                    if (params.length != 2)
                        throw new InvalidParameterException("dealAddDataCommand cmd:" + _cmd + " param:" + _paramStr);
                    _gParam.sdkPrinter.appendPrnStr(" ", 2 * 18, AlignEnum.LEFT, false);//先走两行纸，否则barcode会覆盖前两行
                    alignParam = ParseDispPositionParam(params[0]);
                    result = _gParam.sdkPrinter.appendBarcode(params[1], _gParam.barcodeParam.height, 0,
                            _gParam.barcodeParam.singleBarWidth, BarcodeFormatEnum.CODE_39, alignParam.alignType);
                    break;
                case "qrcode":
                    params = _paramStr.split(" ", 2);
                    if (params.length != 2)
                        throw new InvalidParameterException("dealAddDataCommand cmd:" + _cmd + " param:" + _paramStr);
                    alignParam = ParseDispPositionParam(params[0]);
                    result = _gParam.sdkPrinter.appendQRcode(params[1], _gParam.qrcodeParam.height, 0,
                            _gParam.qrcodeParam.errorCorrectionLevel, alignParam.alignType);
                    break;
                case "image":
                    params = _paramStr.split(" ", 3);
                    if (params.length != 3)
                        throw new InvalidParameterException("dealAddDataCommand cmd:" + _cmd + " param:" + _paramStr);
                    alignParam = ParseDispPositionParam(params[0]);
                    String imageSize[] = params[1].split("\\*", 2);
                    int width = Integer.parseInt(imageSize[0]);
                    int height = Integer.parseInt(imageSize[1]);
                    Bitmap bitmap = null;
                    InputStream is = null;
                    String[] spilts = params[2].split(":");
                    switch (spilts[0]) {
                        case "#logo":
                            int id = Integer.parseInt(spilts[1]);
                            is = _gParam.mContext.getResources().openRawResource(id);
                            bitmap = BitmapFactory.decodeStream(is);
                            break;
                        case "data":
                            String[] datas = spilts[1].split(";");
                            if (datas[0].equals("base64")) {
                                byte[] imgByte = Base64.decode(datas[1], Base64.DEFAULT);
                                is = new ByteArrayInputStream(imgByte);
//                                bitmap = BitmapFactory.decodeByteArray(imgByte, 0, imgByte.length);
                                Bitmap oribitmap = BitmapFactory.decodeByteArray(imgByte, 0, imgByte.length);
                                Matrix matrix = new Matrix();
                                float scaleWidth = ((float) width) / oribitmap.getWidth();
                                float scaleHeight = ((float) height) / oribitmap.getHeight();
                                matrix.postScale(scaleWidth,scaleHeight);
                                bitmap = Bitmap.createBitmap(oribitmap, 0, 0, oribitmap.getWidth(), oribitmap.getHeight(), matrix, true);
//                                if(testMode)
//                                {
//                                    if (oribitmap.getWidth() > 339 || oribitmap.getHeight() > 339) {
//                                        Matrix matrix = new Matrix();
////                                        float scaleValue = ((float)220)/oribitmap.getWidth();
//                                        float scaleValue = 0;
//                                        if (oribitmap.getWidth() == oribitmap.getHeight())
//                                            scaleValue = ((float) 200) / oribitmap.getWidth();
//                                        else
//                                            scaleValue = ((float) 300) / oribitmap.getWidth();
//                                        matrix.postScale(scaleValue, scaleValue);
//                                        bitmap = Bitmap.createBitmap(oribitmap, 0, 0, oribitmap.getWidth(), oribitmap.getHeight(), matrix, true);
//                                    } else
//                                        bitmap = oribitmap;
//                                }
//                                else{
//                                    if(oribitmap.getWidth() > _gParam.printerWidth  || oribitmap.getHeight() > _gParam.printerWidth ){
//                                        Matrix matrix = new Matrix();
////                                        float scaleValue = ((float)220)/oribitmap.getWidth();
//                                        float scaleValue = ((float)200)/oribitmap.getWidth();
//                                        matrix.postScale(scaleValue, scaleValue);
//                                        bitmap = Bitmap.createBitmap(oribitmap, 0, 0, oribitmap.getWidth(), oribitmap.getHeight(), matrix, true);
//                                    } else
//                                        bitmap = oribitmap;
//                                }
                            }
                            break;
                        case "path":
                            bitmap = BitmapFactory.decodeFile(spilts[1]);
                            break;
                        default:
                            break;
                    }
                    if (null == bitmap)
                        break;
                    result = _gParam.sdkPrinter.appendImage(bitmap, alignParam.alignType);
                    break;
                case "pause":

                    break;

            }
            if (result == SdkResult.Success)
                rslt = true;
            else
                rslt = false;
        } catch (Exception e) {
            e.printStackTrace();
            rslt = false;
        }

        return rslt;
    }
}
